<template>
  <div
      class="touch_tab_container"
      ref="TabContainerEl"
      :style="{
        height:height+'px',
    }"
      @touchmove="(e)=>{
        mouseMove(e.touches[0]);
    }"
      @touchstart="(e)=>{
        onMouseDown(e.touches[0]);
    }"
      @touchend="(e)=>{
        onMouseUp(e.touches[0]);
    }"
      @mousemove="mouseMove"
      @mouseleave="onMouseLeave"
      @mousedown="onMouseDown"
      @mouseup="onMouseUp">
    <div
        :class="{
            container:true,
            animation:animation,
        }"
        ref="ContainerEl"
        :style="{
            transform:`translateX(${translateX}px)`,
        }">
      <slot></slot>
    </div>
  </div>
</template>
<script>
//自定义touchTab组件
export default {
  name:'TouchTab',
  data() {
    return {
      height:0,  //总容器高度
      TabContainerEl:undefined,  //总容器元素
      ContainerEl:undefined,
      tabItemEls:[],
      mouseDown:false,  //鼠标是否按下
      translateX:0,  //容器的偏移量
      animation:false,  //是否开启容器动画
      activeIndex:0,
      speed:0,  //移动速度
    };
  },
  computed:{
    translateX_:{  //translateX的代理层
      set(newValue){
        if(!this.ContainerEl) return;
        if(newValue > 0) return;
        if(newValue < this.TabContainerEl.clientWidth-this.ContainerEl.clientWidth) return;
        this.translateX = newValue;
        if(this.mouseDown){  //如果鼠标按下的话计算移动速率
          let oldTranslateX = this.oldTranslateX || newValue;
          let oldDate = this.oldDate || new Date().getTime();
          let newTranslateX = newValue;
          let newDate =new Date().getTime();
          this.speed =  Math.abs((newTranslateX - oldTranslateX)/(newDate - oldDate));
          this.oldTranslateX = newTranslateX;
          this.oldDate = newDate;
        }
      },
      get(){
        return this.translateX;
      },
    },
  },
  watch:{
    activeIndex:{  //当前选项发生变化时向外部暴露当前显示的选项索引
      handler(newVlaue){
        this.$emit('onChange',newVlaue);
      },
      immediate:true,
    },
  },
  mounted(){
    this.TabContainerEl = this.$refs.TabContainerEl;
    this.ContainerEl = this.$refs.ContainerEl;
    this.tabItemEls = this.$refs.ContainerEl.children;
    this.setActiveEl(this.activeIndex);  //设置初始显示item
    const that = this;
    requestAnimationFrame(function func(){  //每一帧都计算样式
      that.computeStyle();
      requestAnimationFrame(func);
    });
  },
  methods:{
    mouseMove(e){  //鼠标移动事件
      if(!this.mouseDown) return;  //必须是鼠标按下
      this.animation = false;
      let clientX = e.clientX - this.lastEnven.clientX;
      this.translateX_ = this.translateX_ + clientX;
      this.lastEnven = e;
    },
    onMouseLeave(){  //鼠标移出事件
      this.mouseDown = false;
      this.lastEnven = undefined;
      this.computeIndex();
    },
    onMouseDown(e){  //鼠标按下事件
      this.mouseDown = true;
      this.lastEnven = e;
    },
    onMouseUp(){  //鼠标抬起事件
      this.mouseDown = false;
      this.lastEnven = undefined;
      this.computeIndex();
    },
    computeStyle(){  //计算样式
      if(this.tabItemEls.length>0){
        this.tabItemEls.forEach(el => {  //设置子元素的宽度与总容器宽度一致
          el.style.width = this.TabContainerEl.clientWidth+'px';
          el.style.minWidth = this.TabContainerEl.clientWidth+'px';
        });
        this.height = this.tabItemEls[this.activeIndex].clientHeight;
      }
    },
    computeIndex(){  //计算索引位置
      let itemWidth = this.TabContainerEl.clientWidth;
      let translateX = Math.abs(this.translateX_);
      let width_ = itemWidth*this.activeIndex - translateX;
      let direction = width_>0?'left':'right';
      width_ = Math.abs(width_);
      if(width_>(itemWidth/2)){  //如果滑动超过了一半
        this.setActiveEl(
            direction=='right'?this.activeIndex+1:this.activeIndex-1,
        );
      }else if(this.speed>0.5){  //表示没有超过一半，可以通过滑动速率和方向判断
        this.setActiveEl(
            direction=='right'?this.activeIndex+1:this.activeIndex-1,
        );
      }else{
        this.setActiveEl(this.activeIndex);
      }
      this.speed = 0;
    },
    setActiveEl(index){  //设置当前显示的item(可外部调用)
      this.animation = true;
      if(index<=0){
        this.activeIndex = 0;
      }else if(index>(this.tabItemEls.length-1)){
        this.activeIndex = this.tabItemEls.length-1;
      }else{
        this.activeIndex = index;
      }
      this.translateX_ = -this.TabContainerEl.clientWidth * this.activeIndex;
    },
  },
}
</script>
<style lang="scss" scoped>
.touch_tab_container{
  width: 100%;
  margin: 0 auto;
  background-color: aquamarine;
  border-radius: 5px;
  height: fit-content;
  overflow: hidden;
  transition: height 0.2s;
  >.container{
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    width:fit-content;
    display: flex;
    transform: translateX(0px);
    >.item{
      min-width: 0;
      width: 0;
      height: fit-content;
    }
  }
  .animation{
    transition: all 0.2s;
    transition-timing-function: cubic-bezier(0.69, 0.05, 0.24, 1.01);
  }
}
</style>

